#include "unittest.h"
#include "base.h"
#include "array.h"
#include "structures.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#define INTEGER(X) (&(int) { X })

static void
test_array(const_pointer data)
{
	struct LqArray* array = lq_array_new(2, sizeof(int));

	assert(lq_array_size(array) == 0);
	assert(lq_array_capacity(array) == 2);

	lq_array_append(array, INTEGER(5), 1);
	lq_array_append(array, INTEGER(7), 1);
	lq_array_append(array, INTEGER(9), 1);

	assert(lq_array_size(array) == 3);
	assert(lq_array_capacity(array) > 2);

	assert(*lq_cast(int*, lq_array_pointer(array)) == 5);
	assert(*lq_cast(int*, lq_array_get(array, 0)) == 5);
	assert(*lq_cast(int*, lq_array_get(array, 1)) == 7);
	assert(*lq_cast(int*, lq_array_get(array, 2)) == 9);
	assert(*lq_cast(int*, lq_array_last(array)) == 9);

	assert(lq_array_remove(array, 1, 1));

	assert(*lq_cast(int*, lq_array_get(array, 0)) == 5);
	assert(*lq_cast(int*, lq_array_get(array, 1)) == 9);
	assert(lq_array_get(array, 2) == 0);

	assert(lq_array_insert(array, 1, INTEGER(3), 1));

	assert(*lq_cast(int*, lq_array_get(array, 0)) == 5);
	assert(*lq_cast(int*, lq_array_get(array, 1)) == 3);
	assert(*lq_cast(int*, lq_array_get(array, 2)) == 9);

	assert(lq_array_replace(array, 0, INTEGER(2), 1));

	assert(*lq_cast(int*, lq_array_get(array, 0)) == 2);
	assert(*lq_cast(int*, lq_array_get(array, 1)) == 3);
	assert(*lq_cast(int*, lq_array_get(array, 2)) == 9);

	assert(lq_array_size(array) == 3);

	lq_array_free(array);
}


static void
test_ptrarray(const_pointer data)
{
	struct LqPtrArray* array = lq_ptr_array_new(2);

	assert(lq_ptr_array_size(array) == 0);
	assert(lq_ptr_array_capacity(array) == 2);

	lq_ptr_array_append(array, "A");
	lq_ptr_array_append(array, "B");
	lq_ptr_array_append(array, "C");

	assert(lq_ptr_array_insert(array, 1, "D"));
	assert(lq_ptr_array_insert(array, 1, "E"));

	assert(lq_ptr_array_size(array) == 5);
	assert(lq_ptr_array_capacity(array) > 2);

	assert(strcmp(lq_ptr_array_get(array, 0), "A") == 0);
	assert(strcmp(lq_ptr_array_get(array, 1), "E") == 0);
	assert(strcmp(lq_ptr_array_get(array, 2), "D") == 0);
	assert(strcmp(lq_ptr_array_get(array, 3), "B") == 0);
	assert(strcmp(lq_ptr_array_get(array, 4), "C") == 0);

	assert(lq_ptr_array_replace(array, 1, "Z") != 0);
	assert(strcmp(lq_ptr_array_get(array, 1), "Z") == 0);

	assert(lq_ptr_array_remove(array, 1) != 0);

	assert(lq_ptr_array_size(array) == 4);

	assert(strcmp(lq_ptr_array_get(array, 0), "A") == 0);
	assert(strcmp(lq_ptr_array_get(array, 1), "D") == 0);
	assert(strcmp(lq_ptr_array_get(array, 2), "B") == 0);
	assert(strcmp(lq_ptr_array_get(array, 3), "C") == 0);

	lq_ptr_array_free(array);
}


static void
test_stack(const_pointer data)
{
	struct LqStack* stack = lq_stack_new();

	assert(lq_stack_size(stack) == 0);

	lq_stack_push(stack, "A");
	lq_stack_push(stack, "B");
	lq_stack_push(stack, "C");
	
	assert(lq_stack_size(stack) == 3);

	assert(strcmp(lq_stack_top(stack), "C") == 0);

	assert(strcmp(lq_stack_below(stack, 0), "C") == 0);
	assert(strcmp(lq_stack_below(stack, 1), "B") == 0);
	assert(strcmp(lq_stack_below(stack, 2), "A") == 0);
	assert(lq_stack_below(stack, 3) == 0);

	assert(lq_stack_pop(stack) != 0);
	
	assert(lq_stack_size(stack) == 2);

	assert(strcmp(lq_stack_top(stack), "B") == 0);
	assert(strcmp(lq_stack_below(stack, 0), "B") == 0);
	assert(strcmp(lq_stack_below(stack, 1), "A") == 0);
	assert(lq_stack_below(stack, 2) == 0);

	lq_stack_free(stack);
}


static void
test_queue(const_pointer data)
{
	struct LqQueue* queue = lq_queue_new();

	assert(lq_queue_size(queue) == 0);

	lq_queue_enqueue(queue, "A");
	lq_queue_enqueue(queue, "B");
	lq_queue_enqueue(queue, "C");


	assert(lq_queue_size(queue) == 3);

	assert(strcmp(lq_queue_front(queue), "A") == 0);
	assert(strcmp(lq_queue_rear(queue), "C") == 0);

	assert(lq_queue_dequeue(queue) != 0);

	assert(strcmp(lq_queue_front(queue), "B") == 0);
	assert(strcmp(lq_queue_rear(queue), "C") == 0);

	assert(strcmp(lq_queue_nth(queue, 0), "B") == 0);
	assert(strcmp(lq_queue_nth(queue, 1), "C") == 0);

	assert(lq_queue_nth(queue, 2) == 0);

	assert(lq_queue_size(queue) == 2);

	lq_queue_free(queue, 0);
}


void 
lq_test_structures(void)
{
        lq_unittest_run("structures.array", test_array, 0, 10);
	lq_unittest_run("structures.ptrarray", test_ptrarray, 0, 10);
	lq_unittest_run("structures.stack", test_stack, 0, 10);
	lq_unittest_run("structures.queue", test_queue, 0, 10);
}

